﻿ ///<reference path="../adapters/jquery/ajax.js" />

(function() {

		function getOptionValue(option) {
			return (option.value == null) ? option.text : option.value;
		}

		var formObj = {
			setValue: function(element, value) {
				element = amp.byId(element);
				switch (element.tagName.toLowerCase()) {
					case "textarea":
					case "input":
						var type = element.type;
						if ((type == 'checkbox' || type == 'radio'))
							element.checked = !!value
						else
							element.value = value;
					case "select":
						var one = amp.isArray(value);
						for (var i = 0; element.options.length; i++) {
							var option = element.options[i];
							var optValue = getOptionValue(option);
							if (one) {
								if (value == optValue) {
									option.selected = true;
									break;
								}
							} else
								option.selected = value.include(optValue);
						}
				}

			},

			getValue: function(element) {
				element = amp.byId(element);
				switch (element.tagName.toLowerCase()) {
					case "textarea":
					case "input":
						var type = element.type;
						if ((type == 'checkbox' || type == 'radio')) {
							if (element.checked)
								return element.value;
							else
								return null;
						}
						return element.value;
					case "select":
						var type = element.type;

						if (type.indexOf("one") > -1) {
							if (element.selectedIndex >= 0)
								return getOptionValue(element.options[element.selectedIndex]);
							return null;
						} else {
							var values = new Array();
							for (var i = 0; i < element.options.length; i++) {
								var option = element.options[i];
								if (option.selected)
									values.push(getOptionValue(option));
							}
							return values;
						}
				}
				return null;
			},

			serialize: function(form) {
				var parameters = "";

				for (var i = 0; i < form.elements.length; i++) {
					var element = form.elements[i];
					var name = element.name;

					if (!name || name.trim() == "")
						continue;

					var value = this.getValue(element);

					amp.array(value).each(function(item) {
						if (item != null)
							parameters += "&" + encodeURIComponent(name) + "=" + encodeURIComponent(item);
					});
				}

				return parameters;
			}

		}

		amp.UI.Form = {
			__namespace: true,
			__type: "amp.UI.Form",
			Util: formObj
		}

		var ruleSet = function(formName, rulesToAdd) {
			this.rules = { form: formName };
			amp.extend(this.rules, rulesToAdd || {});
		}

		ruleSet.prototype = {
			addRules: function(fieldName, rules) {
				this.rules[fieldName] = this.rules[fieldName] || {};
				amp.extend(this.rules[fieldName], rules);
			},

			addRule: function(fieldName, ruleName, args) {
				this.rules[fieldName] = this.rules[fieldName] || {};
				this.rules[fieldName][ruleName] = args;
			},

			toJson: function() {
				return this.rules;
			}
		}



		var validation = function() {
			var forms = [], rules = {};



			this.addRules = function(formName, field, rules) {
				var ruleSet = rules[formName];
				ruleSet[field] = ruleSet.field ? amp.extend(ruleSet[field], rules) : rules;
			}

			this.addSet = function(ruleSet) {
				if (ruleSet.toJson)
					ruleSet = ruleSet.toJson();
				forms.push(ruleSet["form"]);
				rules[ruleSet["form"]] = ruleSet;
				this.initialize(ruleSet["form"]);
				return this;
			}

			this.initialize = function(formsToRun) {
				formsToRun = formsToRun || forms;

				var event = this.event, validators = this.validators;

				amp.array(formsToRun).each(function(formName) {
					var ruleSet = rules[formName];

					for (var element in ruleSet) {
						if (element != "form") {
							amp("#" + element).bind(event, function(e) {
								var item = amp.event.getTarget(e);
								validators.run(item, ruleSet[element]);
							});
						}
					}

					amp(formName).onsubmit(function(e) {
						var formElement = amp.byId(form);
						if (!formElement.pass) {

							amp.event.stop(e);

							var pass = true, ruleSet = rules[form];

							for (var element in ruleSet) {
								var item = amp.byId(element), itemRules = ruleSet[element];


								if (!itemRules.pass) {
									validators.run(item, itemRules);
									if (!itemRules.pass)
										pass = false;
								}

							}

							if (pass) {
								formElement.pass = true;
								formElement.submit();
							}
						}
					});
				});
			}
		}

		validation.prototype = {
			event: "blur",
			createSet: function(formName, rules) {
				///<returns type="amp.UI.Form.RuleSet"></returns>
				return new ruleSet(formName, rules);
			},
			validators: {

				suffix: "-message",
				"class": "error",

				required: function(value, rules) {
					var args = rules.required;
					args["message"] = args["message"] || "* required";
					return ((args["default"]) != value);
				},

				ajax: function(value, rules) {
					var args = rules.ajax;

					if (!args.options.onComplete) {
						args.options.onComplete = function(o) {
							if (o.responseText == "success") {
								rules.pass = true;
								amp(args.notice).html(args.message).hide();
							} else {
								args.message = o.responseText;
								amp(args.notice).html(args.message).show();
								rules.pass = false;
							}
						}
					}

					amp.ajax(args.url + encodeURIComponent(value),
						args.options)

					return false;
				},

				regex: function(value, rules) {
					var args = rules.regex;
					args["message"] = args["message"] || "* invalid format";
					if (value.trim().length == 0)
						return false;
					var expression = new RegExp(args["with"], args["options"] || "");
					var matches = expression.exec(value);
					return !(matches == null || value != matches[0]);
				},

				confirm: function(value, rules) {
					var args = rules.confirm;
					args["message"] = args["message"] || "* does not match " + args.compare;
					return (amp.byId(args.compare).value == value);
				},

				run: function(element, rules) {
					var value = element.value,
						s = this.suffix,
						c = this["class"],
						pass = true,
						ajax = false,
						args = null,
						notice = amp.byId(element.id + s);

					if (!notice) {
						amp(element).insert({ after: "<span id='" + (element.id + s) + "' class='" + c + "'></span>" });
						notice = amp("#" + element.id + s).get();
					}

					for (var rule in rules) {
						if (rule == "pass")
							continue;

						rules[rule].notice = notice;

						if (rule == "ajax") {
							ajax = rule;
							continue;
						}
						pass = this[rule](value, rules);

						if (!pass) {
							args = rules[rule];
							amp(notice).html(args.message).show();
							break;
						}
					}

					if (ajax) {
						pass = false;
						args = rules[ajax].notice = notice;
						args.notice = notice;
						amp(notice).html(args.loadMessage || "validating...").show();
						this[ajax](value, rules);
					}

					rules["pass"] = pass;
					if (pass)
						amp(notice).hide();
				}
			}

		}

		amp["class"]("amp.UI.Form.Validation", null, validation);
		amp["class"]("amp.UI.Form.RuleSet", null, ruleSet);

		amp.getValidation = function() {
			///<returns type="amp.UI.Form.Validation"><returns>
			if (!amp.Cache.validation)
				amp.Cache.validation = new validation();
			return amp.Cache.validation;
		}

	})()